/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package AccesoDatos.DAOSocket;

import AccesoDatos.IDAO.IDAOArchivo;
import ObjetoDominio.Archivo;
import ObjetoDominio.ArchivoXML;
import ObjetoDominio.Servidor;
import ObjetoDominio.Usuario;
import Proxy.ProxyArchivo;
import Proxy.ProxyUsuario;
import Session.Session;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.List;

/**
 *Clase que implementa la interfaz IDAOArchivo
 * para el caso particular de sockets
 * @author familia
 */
public class DAOArchivoSocket implements IDAOArchivo {

    Servidor _servidor;
    
    /**
     * Constructor de la clase
     * @param servidor datos del servidor para la comunicacion
     */
    public DAOArchivoSocket(Servidor servidor){
        _servidor = servidor;
    }
    
    /**
     * metodo que descarga los archivos desde la fuente por socket
     * @param arhivo datos del archivo a descargar
     */
    @Override
    public void DescargarArchivo(Archivo arhivo) {
        try
        {
            _servidor.AbrirConexion();            
            OutputStream flujoSalida = _servidor.getViaComunicacion().getOutputStream();
            DataOutputStream salida = new DataOutputStream( flujoSalida );
            salida.writeUTF(ArchivoXML.CrearMensaje("descargar"));
            salida.writeUTF(ProxyUsuario.TransformarUsuarioXml(Session.getUsuarioConectador()));
            salida.writeUTF(ArchivoXML.CrearMensaje(arhivo.getNombre()));
            salida.writeUTF(ArchivoXML.CrearMensaje(String.valueOf(arhivo.getDescargado())));
            FileOutputStream fos;
            if(arhivo.getDescargado() == 0)
                fos = new FileOutputStream(arhivo.getNombre());
            else
                fos = fos = new FileOutputStream(arhivo.getNombre(),true);
            ObjectInputStream ois = new ObjectInputStream(_servidor.getViaComunicacion()
                    .getInputStream());
            Object mensajeAux;
            Archivo mensajeRecibido;
            do
            {
                mensajeAux = ois.readObject();
                if (mensajeAux instanceof Archivo)
                {
                    mensajeRecibido = (Archivo) mensajeAux;
                     fos.write(mensajeRecibido.getContenidoFichero(),
                             0, mensajeRecibido.getBytesValidos());
                    arhivo.setDescargado(arhivo.getDescargado() +
                            mensajeRecibido.getBytesValidos());
                } 
                else{
                    System.err.println("Mensaje no esperado "
                            + mensajeAux.getClass().getName());
                    break;
                }
            } while (!mensajeRecibido.isUltimoMensaje());
            fos.close();
            ois.close();
            _servidor.CerrarConexion();

        } catch (Exception e)
        {
            System.out.println(e);
        }
    }
    
    /**
     * Metodo que realiza un cast de int a long de forma segura
     * @param l
     * @return 
     */
    private static int safeLongToInt(long l) {
        if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
            throw new IllegalArgumentException
                (l + " cannot be cast to int without changing its value.");
        }
        return (int) l;
    }

    /**
     * Metodo que reanuda la descarga de un archivo seleccionado por socket
     * @param arhivo datos del archivo a descargar
     */
    @Override
    public void ReanudarDescarga(Archivo arhivo) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * metodo que Carga el archivo seleccionado por socket
     * @param arhivo datos del archivo a descargar
     */
    @Override
    public void CargarArchivo(Archivo arhivo) {
        try
        {
             _servidor.AbrirConexion();            
            OutputStream flujoSalida = _servidor.getViaComunicacion().getOutputStream();
            InputStream flujoEntrada = _servidor.getViaComunicacion().getInputStream();
            DataOutputStream salida = new DataOutputStream( flujoSalida );
            salida.writeUTF(ArchivoXML.CrearMensaje("cargar"));
            salida.writeUTF(ProxyUsuario.TransformarUsuarioXml(Session.getUsuarioConectador()));
            salida.writeUTF(ArchivoXML.CrearMensaje(arhivo.getNombre()));
            salida.writeUTF(ArchivoXML.CrearMensaje(String.valueOf(arhivo.getTamaño())));
            DataInputStream entrada = new DataInputStream(flujoEntrada);
            arhivo.setDescargado(Long.parseLong(ArchivoXML.ObtenerMensaje(entrada.readUTF())));
            
            if(arhivo.getDescargado()!= -1){
                
                boolean enviadoUltimo=false;
                ObjectOutputStream oos = new ObjectOutputStream(flujoSalida);
                FileInputStream fis = new FileInputStream(arhivo.getRuta());
                Archivo mensaje = new Archivo();
                mensaje.setNombre(arhivo.getNombre());
                int leidos = fis.read(mensaje.getContenidoFichero());
                int tamaño = leidos;
                if(arhivo.getDescargado() != 0)
                    arhivo.setDescargado(arhivo.getDescargado());
                while (leidos > -1)
                {
                    mensaje.setBytesValidos(leidos);
                    if (leidos < Archivo.LONGITUD_MAXIMA)
                    {
                        mensaje.setUltimoMensaje(true);
                        enviadoUltimo=true;
                    }
                    else
                        mensaje.setUltimoMensaje(false);
                    
                    if(tamaño > arhivo.getDescargado()){
                        //Thread.sleep(20);
                        oos.writeObject(mensaje);
                        entrada.readUTF();
                        arhivo.setDescargado(arhivo.getDescargado() +
                                mensaje.getBytesValidos());
                    }

                    if (mensaje.isUltimoMensaje())
                        break;
                    mensaje = new Archivo();
                    mensaje.setNombre(arhivo.getNombre());
                    leidos = fis.read(mensaje.getContenidoFichero());
                    tamaño = tamaño + leidos;
                }

                if (enviadoUltimo==false)
                {
                    mensaje.setUltimoMensaje(true);
                    mensaje.setBytesValidos(0);
                    oos.writeObject(mensaje);
                    entrada.readUTF();
                }
                oos.close();
            }
        }catch (Exception e)
        {
            System.out.println(e);
        }
    }

    /**
     * metodo que reanuda la craga de un archivo del cliente por socket
     * @param arhivo datos del archivo a descargar
     */
    @Override
    public void ReanudarCargar(Archivo arhivo) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public List<Archivo> ObtenerListaArchivo(Usuario usuario) {
        try {
            _servidor.AbrirConexion();
            OutputStream flujoSalida = _servidor.getViaComunicacion().getOutputStream();
            InputStream flujoEntrada = _servidor.getViaComunicacion().getInputStream();
            DataOutputStream salida = new DataOutputStream( flujoSalida );
            DataInputStream entrada = new DataInputStream(flujoEntrada);
            salida.writeUTF(ArchivoXML.CrearMensaje("obtenerListaArchivos"));
            salida.writeUTF(ProxyUsuario.TransformarUsuarioXml(usuario));
            String xml = entrada.readUTF();
            return ProxyArchivo.ObtenerListaArchivoXml(xml);
            
        }catch(Exception e){
            System.out.println(e);
            return null;
        }
    }

   
    
}
